package com.youshang520i.ratelimiter.config.cglib;

import com.youshang520i.ratelimiter.config.annotation.RateLimiter;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * @author youshang
 */
public class CglibProxy implements MethodInterceptor {
    private com.google.common.util.concurrent.RateLimiter initRateLimiter;

    public CglibProxy(com.google.common.util.concurrent.RateLimiter rateLimiter) {
        initRateLimiter = rateLimiter;
    }

    /**
     * 回调接口的方法
     * 回调接口的方法执行的条件是：代理对象执行目标方法时会调用回调接口的方法
     *
     * @param obj
     * @param method
     * @param args
     * @param methodProxy
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//        System.out.println(String.format("方法名: %s",method.getName()));
//        System.out.println(String.format("开始执行日期: %s ", startTime));

        RateLimiter annotation = method.getAnnotation(RateLimiter.class);
        if (null != annotation) {
            if (!this.tryAcquire(initRateLimiter, annotation)) {
                Object o = null;
                if (!"".equals(annotation.fallback()) && null != annotation.fallback()) {
                    for (Method method1 : obj.getClass().getMethods()) {
                        if (method1.getName().equals(annotation.fallback())) {
                            method1.invoke(obj, args);
                        }
                    }
                }
                return o;
            }
        }
        return methodProxy.invokeSuper(obj, args);
    }

    /**
     * 尝试获取令牌
     */
    public boolean tryAcquire(com.google.common.util.concurrent.RateLimiter rateLimiter, RateLimiter annotation) {

        //获取一个许可
        // return rateLimiter.tryAcquire(1);
        //获取一个许可最多等待100毫秒
        return rateLimiter.tryAcquire(annotation.permits(), annotation.timeout(), TimeUnit.MILLISECONDS);
    }
}
